﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Data;
using Odyssey.Behaviors;
using Odyssey.Utils;

namespace Odyssey.Controls
{
    /// <summary>
    /// Textbox replacement which renders 90% faster.
    /// </summary>
    [TemplatePart(Name = "ContentElement", Type = typeof(Border))]
    [TemplateVisualState(Name = "ReadOnly", GroupName = "CommonStates")]
    [TemplateVisualState(Name = "Normal", GroupName = "CommonStates")]
    [TemplateVisualState(Name = "Disabled", GroupName = "CommonStates")]
    [TemplateVisualState(Name = "Unfocused", GroupName = "FocusStates")]
    [TemplateVisualState(Name = "Focused", GroupName = "FocusStates")]
    public class OdcTextBox : Control
    {
        public OdcTextBox()
            : base()
        {
            DefaultStyleKey = typeof(OdcTextBox);

            this.IsEnabledChanged += new DependencyPropertyChangedEventHandler(OnEnabledChanged);
            Unloaded += new RoutedEventHandler(OdcTextBox_Unloaded);
        }

        void OdcTextBox_Unloaded(object sender, RoutedEventArgs e)
        {
            IsActive = false;
        }

        void OnEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            bool isEnabled = (bool)e.NewValue;
            if (Parent!=null) VisualStateManager.GoToState(this, isEnabled ? "Normal" : "Disabled", true);
            
        }

        private TextBox textBox;
        private int selectionLength;
        private int selectionStart;
        private bool isActive;



        public bool SelectAllWhenFocused
        {
            get { return (bool)GetValue(SelectAllWhenFocusedProperty); }
            set { SetValue(SelectAllWhenFocusedProperty, value); }
        }

        public static readonly DependencyProperty SelectAllWhenFocusedProperty =
            DependencyProperty.Register("SelectAllWhenFocused", typeof(bool), typeof(OdcTextBox), new PropertyMetadata(true));



        public bool IsActive
        {
            get { return isActive; }
            private set
            {
                if (IsReadOnly) value = false;
                if (isActive != value)
                {
                    isActive = value;
                    OnActiveChanged(value);
                }
            }
        }

        public int SelectionStart
        {
            get { return selectionStart; }
            set
            {
                if (selectionStart != value)
                {
                    selectionStart = value;
                    Select(value, selectionLength);
                }
            }
        }

        public int SelectionLength
        {
            get { return selectionLength; }
            set
            {
                if (selectionLength != value)
                {
                    selectionLength = value;
                    Select(selectionStart, value);
                }
            }
        }

        protected string ActualText
        {
            get { return Text ?? string.Empty; }
        }

        public bool AcceptReturn
        {
            get { return (bool)GetValue(AcceptReturnProperty); }
            set { SetValue(AcceptReturnProperty, value); }
        }



        public bool IsReadOnly
        {
            get { return (bool)GetValue(IsReadOnlyProperty); }
            set { SetValue(IsReadOnlyProperty, value); }
        }

        public static readonly DependencyProperty IsReadOnlyProperty =
            DependencyProperty.Register("IsReadOnly", typeof(bool), typeof(OdcListBox), new PropertyMetadata(false));



        public static readonly DependencyProperty AcceptReturnProperty =
            DependencyProperty.Register("AcceptReturn", typeof(bool), typeof(OdcTextBox), new PropertyMetadata(false));


        public InputScope InputScope
        {
            get { return (InputScope)GetValue(InputScopeProperty); }
            set { SetValue(InputScopeProperty, value); }
        }

        public static readonly DependencyProperty InputScopeProperty =
            DependencyProperty.Register("InputScope", typeof(InputScope), typeof(OdcTextBox), new PropertyMetadata(null));


        public string Text
        {
            get { return (string)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }

        public static readonly DependencyProperty TextProperty =
            DependencyProperty.Register("Text", typeof(string), typeof(OdcTextBox), new PropertyMetadata(string.Empty, OnTextChanged));


        private static void OnTextChanged(DependencyObject o, DependencyPropertyChangedEventArgs args)
        {
            (o as OdcTextBox).OnTextChanged(args.OldValue as string, args.NewValue as string);
        }

        protected virtual void OnTextChanged(string oldValue, string newValue)
        {
            if (isActive && textBox != null) textBox.Text = newValue;
            var eh = TextChanged;
            if (eh != null) eh(this, EventArgs.Empty);
        }



        public ControlTemplate TextBoxTemplate
        {
            get { return (ControlTemplate)GetValue(TextBoxTemplateProperty); }
            set { SetValue(TextBoxTemplateProperty, value); }
        }

        // Using a DependencyProperty as the backing store for TextBoxTemplate.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TextBoxTemplateProperty =
            DependencyProperty.Register("TextBoxTemplate", typeof(ControlTemplate), typeof(OdcTextBox), new PropertyMetadata(null));




        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            VisualStateManager.GoToState(this, IsEnabled ? "Normal" : "Disabled", false);

        }

        protected void OnActiveChanged(bool isActive)
        {
            if (isActive)
            {
                textBox = new TextBox();
                textBox.LostFocus += new RoutedEventHandler(textBox_LostFocus);
                textBox.VerticalAlignment = System.Windows.VerticalAlignment.Stretch;
                textBox.HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch;
                textBox.Text = Text ?? string.Empty;
                textBox.FontFamily = this.FontFamily;
                textBox.FontStyle = this.FontStyle;
                textBox.FontSize = this.FontSize;
                textBox.Foreground = this.Foreground;
                if (InputScope != null) textBox.InputScope = InputScope;
                textBox.Template = TextBoxTemplate;
                textBox.TextChanged += (s, e) =>
                    {
                        Text = textBox.Text;
                        Select(textBox.SelectionStart, textBox.SelectionLength);
                    };

                textBox.Select(selectionStart, selectionLength);

                (GetTemplateChild("PART_Text") as FrameworkElement).Visibility = System.Windows.Visibility.Collapsed;
                var content = GetTemplateChild("ContentElement") as Border;
                content.Child = textBox;
                content.Visibility = System.Windows.Visibility.Visible;
                textBox.Background = new SolidColorBrush(Color.FromArgb(0, 0, 0, 0));
                textBox.Dispatcher.BeginInvoke(() =>
                {
                    if (textBox != null)
                    {
                        this.Focus();
                        textBox.Focus();
                        if (SelectAllWhenFocused) textBox.SelectAll();
                    }
                });
            }
            else
            {
                Text = textBox.Text;
                Select(textBox.SelectionStart, textBox.SelectionLength);
                (GetTemplateChild("PART_Text") as FrameworkElement).Visibility = System.Windows.Visibility.Visible;
                var content = GetTemplateChild("ContentElement") as Border;
                content.Child = null;
                content.Visibility = System.Windows.Visibility.Collapsed;
                textBox.Text = string.Empty;
                textBox.InputScope = null;
                textBox = null;
            }
        }

        void textBox_LostFocus(object sender, RoutedEventArgs e)
        {

            IsActive = false;
        }

        protected override void OnManipulationCompleted(ManipulationCompletedEventArgs e)
        {
            base.OnManipulationCompleted(e);
            if (!e.Handled && !e.IsInertial)
            {
                var v = e.TotalManipulation.Translation;
                if (v.X == 0d && v.Y == 0d)
                {
                    TiltEffect.StopTiltReturnStoryboardAndCleanup();
                    e.Handled = true;
                    IsActive = true;
                }
            }
        }

        protected override void OnGotFocus(RoutedEventArgs e)
        {
            IsActive = true;
            base.OnGotFocus(e);
        }



        public void Select(int start, int length)
        {
            if (selectionStart != start || selectionLength != length)
            {
                selectionStart = start;
                selectionLength = length;

                if (isActive)
                {
                    textBox.Select(start, length);
                }
            }
        }

        public void SelectAll()
        {
            Select(0, ActualText.Length);
        }

        public event EventHandler TextChanged;


    }
}
